<template>
  <a-modal
    :align-center="false"
    :body-style="{ background: 'var(--color-fill-1)', borderRadius: '4px' }"
    :mask-closable="true"
    :modal-style="{ borderRadius: '4px' }"
    :visible="dialog.visible"
    :width="632"
    esc-to-close
    hide-title
    modal-class="app-search"
    @cancel="handleModelCancel"
    @keydown.enter="onHandleSelect"
  >
    <div class="app-search-card">
      <a-input
        v-model.trim="searchValue"
        allow-clear
        placeholder="请输入关键词搜索"
        style="margin-bottom: 10px"
        @clear="clearInfo"
        @input="handleInput"
      >
        <template #prefix>
          <icon-search />
        </template>
      </a-input>
      <div ref="resultsContainer" class="app-search-card-result">
        <div v-if="searchValue != ''">
          <ul v-if="filteredData.length" class="result-ul">
            <li
              v-for="(item, index) in filteredData"
              :key="index"
              ref="menuItems"
              :class="index === activeIndex ? 'result-ul-li-on' : ''"
              class="result-ul-li"
              @click="onHandleSelect"
              @mouseenter="setActiveIndex(index, item)"
            >
              <a href="javascript:">
                <div class="result-ul-li-icon">
                  <icon-apps :size="16" />
                </div>
                <div class="result-ul-li-content">{{ item.title }}</div>
                <div class="result-ul-li-action">
                  <icon-redo :rotate="180" />
                </div>
              </a>
            </li>
          </ul>
        </div>
        <div v-else class="no-result">
          <a-empty />
        </div>
      </div>
    </div>
    <template #footer>
      <div class="app-search-card-footer">
        <ul class="commands">
          <li>
            <span class="commands-icon">
              <icon-redo :rotate="180" />
            </span>
            <span>确认</span>
          </li>
          <li>
            <span class="mr-2 commands-icon">
              <icon-arrow-up />
            </span>
            <span class="commands-icon">
              <icon-arrow-down />
            </span>
            <span>切换</span>
          </li>
          <li>
            <span class="commands-icon">
              <icon-close />
            </span>
            <span>ESC关闭</span>
          </li>
        </ul>
      </div>
    </template>
  </a-modal>
</template>

<script lang="ts" name="SearchMenu" setup>
import { reactive } from "vue";
import DialogOption from "../../types/global";
import usePermissionStore from "@/store/modules/permission";
import { RouteRecordRaw } from "vue-router";
import { isHttp } from "@/utils/validate";
import { getNormalPath } from "@/utils/asiainfo";

type Router = Array<{
  path: string;
  icon: string;
  title: string[];
}>;

const activeIndex = ref(-1);

const routes = computed(() => usePermissionStore().routes);

const dialog = reactive<DialogOption>({
  visible: false,
  title: ""
});
const router = useRouter();
const resultsContainer = ref(null);

const filteredData = ref<any>([]);

const menuItems = ref([]);

const routerInfo = ref({});

const menuList = ref<any>([]);

const searchValue = ref("");

const handleModelCancel = () => {
  dialog.visible = false;
};

const show = async () => {
  dialog.visible = true;
  menuList.value = generateRoutes(routes.value, searchValue.value);
};

const generateRoutes = (routes: RouteRecordRaw[], basePath = "", prefixTitle: string[] = []) => {
  let res: Router = [];
  routes.forEach((r: any) => {
    if (!r.hidden) {
      const p = r.path.length > 0 && r.path[0] === "/" ? r.path : "/" + r.path;
      const data: any = {
        path: !isHttp(r.path) ? getNormalPath(basePath + p) : r.path,
        icon: r.meta?.icon,
        title: [...prefixTitle]
      };
      if (r.meta && r.meta.title) {
        data.title = [...data.title, r.meta.title];
        if (r.redirect !== "noRedirect") {
          res.push(data);
        }
      }
      if (r.children) {
        const tempRoutes = generateRoutes(r.children, data.path, data.title);
        if (tempRoutes.length >= 1) {
          res = [...res, ...tempRoutes];
        }
      }
    }
  });
  res.forEach((item: any) => {
    if (item.title instanceof Array) {
      item.title = item.title.join("/");
    }
  });
  return res;
};

const handleInput = (value: string, ev: Event) => {
  filteredData.value = [];
  filteredData.value = menuList.value.filter((item: any) => {
    const titleSplits = item.title.split("/");
    return titleSplits[titleSplits.length - 1].indexOf(searchValue.value) > -1;
  });
};

const clearInfo = () => {
  routerInfo.value = {};
  activeIndex.value = -1;
};

const setActiveIndex = (index: any, item: any) => {
  activeIndex.value = index;
  Object.assign(routerInfo.value, item);
};

// 向上切换
const handleUp = () => {
  if (filteredData.value.length > 0) {
    if (activeIndex.value > 0) {
      activeIndex.value -= 1;
    } else {
      activeIndex.value = filteredData.value.length - 1; // 回到最后一项
    }
    scrollToActiveItem();
  }
};

// 当前菜单选中时
const onHandleSelect = () => {
  if (activeIndex.value !== -1) {
    const paths: any = filteredData.value[activeIndex.value].path;
    if (isHttp(paths)) {
      const pIndex = paths.indexOf("http");
      window.open(paths.substring(pIndex, paths.length), "_blank");
    } else {
      router.push(paths);
    }
    searchValue.value = "";
    handleModelCancel();
  }
};

// 向下切换
const handleDown = () => {
  if (filteredData.value.length > 0) {
    if (activeIndex.value < filteredData.value.length - 1) {
      activeIndex.value += 1;
    } else {
      activeIndex.value = 0; // 回到第一项
    }
    scrollToActiveItem();
  }
};

// 滚动到当前高亮的项
const scrollToActiveItem = () => {
  nextTick(() => {
    const container: any = resultsContainer.value;
    const items: any = menuItems.value;
    if (container && items[activeIndex.value]) {
      const activeItem = items[activeIndex.value];
      const itemTop = activeItem.offsetTop;
      const itemBottom = itemTop + activeItem.offsetHeight;
      const containerTop = container.scrollTop;
      const containerBottom = containerTop + container.clientHeight;
      if (itemBottom > containerBottom) {
        // 如果当前项在容器的下方不可见区域
        container.scrollTop = itemBottom - container.clientHeight;
      } else if (itemTop < containerTop) {
        // 如果当前项在容器的上方不可见区域
        container.scrollTop = itemTop - 80;
      }
    }
  });
};

defineExpose({
  show
});

onKeyStroke("ArrowUp", handleUp);
onKeyStroke("ArrowDown", handleDown);
onKeyStroke("Escape", handleModelCancel);
onKeyStroke("Enter", onHandleSelect);
</script>

<style lang="less" scoped>
.app-search-card-footer {
  align-items: center;
  background: var(--color);
  border-radius: 0 0 8px 8px;
  box-shadow: var(--box-shadow);
  display: flex;
  flex-shrink: 0;
  height: 44px;
  padding: 0 14px;
  position: relative;
  -webkit-user-select: none;
  -moz-user-select: none;
  user-select: none;
  width: 100%;

  .commands {
    display: flex;
    align-items: center;

    li span {
      color: #969faf;
    }

    li.active {
      background-color: #ffffff;
      color: #1890ff;
    }

    li {
      display: flex;
      align-items: center;
      margin-right: 14px;
      padding-left: 1px;
    }

    ul {
      list-style: none;
      margin: 0;
      padding: 0;
    }
  }

  .commands-icon {
    align-items: center;
    background: linear-gradient(-225deg, var(--color), var(--color));
    border-radius: 2px;
    box-shadow:
      inset 0 -2px #cdcde6,
      inset 0 0 1px 1px #fff,
      0 1px 2px 1px #1e235a66;
    display: flex;
    height: 18px;
    justify-content: center;
    margin-right: 0.4em;
    padding-bottom: 2px;
    width: 20px;
  }
}

.mr-2 {
  margin-right: 0.5rem;
}

.app-search-card {
  width: 100%;
  padding: 0;
  background: var(--color);
  box-shadow: var(--box-shadow);
}

.app-search-card-result {
  max-height: 472px;
  overflow-y: scroll;

  .result-ul {
    list-style: none;
    padding: 0;
  }

  .result-ul-li-on a {
    background-color: #2d8cf0;
    color: #fff;
  }

  .result-ul-li {
    border-radius: 4px;
    display: flex;
    padding-bottom: 8px;
    position: relative;
  }

  .no-result {
    font-size: 0.9em;
    margin: 0 auto;
    padding: 0;
    text-align: center;
    width: 80%;
  }

  .result-ul-li-icon {
    font-size: 18px;
  }

  .result-ul-li a {
    display: flex;
    align-items: center;
    background: var(--color-fill-3);
    border-radius: 4px;
    padding: 0 12px;
    width: 100%;
    color: #333639;
    border-bottom: 1px solid var(--color-fill-4);
  }

  .result-ul-li-on a {
    background-color: #2d8cf0;
    color: #fff;
  }

  .result-ul-li-content {
    align-items: center;
    color: var(--text-color);
    display: flex;
    flex-direction: row;
    height: 56px;
    padding-left: 6px;
    padding-right: 12px;
    flex: 1;
    box-sizing: border-box;
  }
}
</style>
